using DataAnalyticsTools.Models;
using System;
using System.Collections.Generic;
using System.Linq;

namespace DataAnalyticsTools.Core.AnomalyPointDetect
{
    /// <summary>
    /// MAD (Median Absolute Deviation) 中位数绝对偏差异常检测器
    /// 基于中位数的稳健统计方法，对极端异常值不敏感
    /// 适用于包含大量异常值的时间序列数据
    /// </summary>
    public static class MADDetector
    {
        /// <summary>
        /// 使用MAD方法检测时间序列中的异常点
        /// </summary>
        /// <param name="data">时间序列数据（一维数组）</param>
        /// <param name="threshold">修正Z-score阈值，默认3.5（相当于Z-score的3.5倍）</param>
        /// <returns>异常检测结果</returns>
        /// <example>
        /// 输入:
        ///   data = [10, 11, 10.5, 10.2, 50, 10.3, 10.1]  // 50是异常点
        ///   threshold = 3.5
        /// 输出:
        ///   AnomalyPoints = [Index: 4, Value: 50]  // 索引4（值50）的修正Z-score超过阈值
        /// </example>
        public static AnomalyInfo Detect(
            float[] data,
            float threshold = 3.5f)
        {
            if (data == null || data.Length == 0)
            {
                return new AnomalyInfo
                {
                    Method = "MAD",
                    AnomalyScores = Array.Empty<float>(),
                    Threshold = threshold,
                    AnomalyPoints = new List<AnomalyPoint>(),
                    BaselineValues = Array.Empty<float>(),
                    UpperBounds = Array.Empty<float>(),
                    LowerBounds = Array.Empty<float>()
                };
            }

            int n = data.Length;

            // 计算中位数
            float median = MathHelper.CalculateMedian(data);

            // 计算绝对偏差
            var absoluteDeviations = data.Select(x => Math.Abs(x - median)).ToArray();

            // 计算MAD（绝对偏差的中位数）
            float mad = MathHelper.CalculateMedian(absoluteDeviations);

            // 避免除以零
            if (mad < float.Epsilon)
            {
                return new AnomalyInfo
                {
                    Method = "MAD",
                    AnomalyScores = new float[n],
                    Threshold = threshold,
                    AnomalyPoints = new List<AnomalyPoint>(),
                    BaselineValues = Enumerable.Repeat(median, n).ToArray(),
                    UpperBounds = Enumerable.Repeat(median, n).ToArray(),
                    LowerBounds = Enumerable.Repeat(median, n).ToArray()
                };
            }

            // 计算修正Z-score（Modified Z-score）
            // 使用常数0.6745，使MAD与标准差在正态分布下等价
            const float normalConstant = 0.6745f;
            var scores = new float[n];
            for (int i = 0; i < n; i++)
            {
                scores[i] = Math.Abs((data[i] - median) / (mad / normalConstant));
            }

            // 计算边界
            float madScaled = mad / normalConstant;
            var baselineValues = Enumerable.Repeat(median, n).ToArray();
            var upperBounds = Enumerable.Repeat(median + threshold * madScaled, n).ToArray();
            var lowerBounds = Enumerable.Repeat(median - threshold * madScaled, n).ToArray();

            // 识别异常点
            var anomalyPoints = new List<AnomalyPoint>();
            for (int i = 0; i < n; i++)
            {
                if (scores[i] > threshold)
                {
                    var anomalyType = data[i] > median ? AnomalyType.High : AnomalyType.Low;
                    anomalyPoints.Add(new AnomalyPoint
                    {
                        Index = i,
                        Value = data[i],
                        Score = scores[i],
                        Type = anomalyType,
                        Deviation = scores[i],
                        Reason = $"值 {data[i]:F2} 的修正Z-score为 {scores[i]:F2}，显著偏离中位数 {median:F2}"
                    });
                }
            }

            // 计算总体严重程度和置信度
            var severity = anomalyPoints.Any() ? anomalyPoints.Max(p => p.Score) : 0f;

            // 置信度基于样本量和分布稳定性
            // 1. 样本量因子：样本越多越可靠 (最大到30个样本时达到1.0)
            float sampleFactor = Math.Min(1.0f, n / 30.0f);

            // 2. 稳定性因子：MAD相对于中位数越小越稳定
            float madRelative = mad / (Math.Abs(median) + 1e-6f);
            float stabilityFactor = madRelative < 0.5f ? 1.0f - madRelative : 0.5f / (madRelative + 0.1f);

            // 综合置信度 = 样本量因子 * 稳定性因子
            var confidence = sampleFactor * stabilityFactor;

            return new AnomalyInfo
            {
                Method = "MAD",
                AnomalyScores = scores,
                Threshold = threshold,
                AnomalyPoints = anomalyPoints,
                Severity = severity,
                Confidence = confidence,
                BaselineValues = baselineValues,
                UpperBounds = upperBounds,
                LowerBounds = lowerBounds
            };
        }
    }
}
